package HashMap.Nodo.Operaciones;

import HashMap.Nodo.Clase;
import HashMap.Nodo.Nodo;
import HashMap.Nodo.Operacion;
import HashMap.GenerarCodigoNASM;
import HashMap.Nodo.Categoria;
import HashMap.Nodo.Subclases.Escalar;
import HashMap.Pila;

public class OperacionesDePunteros implements Operacion {

    private Nodo nodoInicial;
    private Nodo nodoDefinitivo;

    public OperacionesDePunteros(Nodo nodoInicial) {
        this.nodoInicial = nodoInicial;
    }

    public OperacionesDePunteros(Nodo nodoInicial, Nodo nodoDefinitivo) {
        this.nodoInicial = nodoInicial;
        this.nodoDefinitivo = nodoDefinitivo;
    }

    @Override
    public int getLongitud() {
        throw new UnsupportedOperationException("Operación no soportada");
    }

    @Override
    public String generarCodigoNASM() {
        switch (nodoInicial.getOperacion()) {
            case "MULTIPLICACION":
                return generarCodigoNASMacceso();
            case "AMPERSON":
                return generarCodigoNASMasignacion();
            case "MALLOC":
                return generarCodigoNASMmalloc();
            case "FREE":
                return generarCodigoNASMfree();
            default:
                return null;
        }
    }

    @Override
    public Nodo generarNodo(String tokenOperacion) {
        switch (tokenOperacion) {
            case "MULTIPLICACION":
                return acceso();
            case "AMPERSON":
                return asignacion();
            case "MALLOC":
                return malloc();
            case "FREE":
                return free();
            default:
                return null;
        }
    }

    private Nodo acceso() {
        if (nodoInicial.getNivelDeIndireccion() > 1) {
            GenerarCodigoNASM generador = GenerarCodigoNASM.getInstancia();
            String nombre = generador.getNombreVariableAuxiliar();
            nodoInicial.setOperacion("MULTIPLICACION");
            nodoDefinitivo = new Escalar(nombre, nodoInicial.getTipoBasicoDeDatos(), Categoria.VARIABLE, nodoInicial.getNivelDeIndireccion() - 1, "MULTIPLICACION");
            Pila.getInstancia().addNodoALaTablaSuperior(nodoDefinitivo);
            return nodoDefinitivo;
        } else {
            throw new RuntimeException("El nivel de indirección debe ser superior a 1...");
        }
    }

    private Nodo asignacion() {
        if ((nodoInicial.getTipoBasicoDeDatos() == nodoDefinitivo.getTipoBasicoDeDatos())
                && ((nodoInicial.getNivelDeIndireccion() == nodoDefinitivo.getNivelDeIndireccion())
                || (nodoInicial.getNivelDeIndireccion() == 1 && nodoDefinitivo.getNivelDeIndireccion() == 0))) {
            String nombre = nodoInicial.getNombre();
            nodoInicial = nodoDefinitivo.copiarNodo();
            nodoInicial.clearNombre();
            nodoInicial.setNombre(nombre);
            nodoInicial.setOperacion("AMPERSON");
            return nodoInicial;
        } else {
            throw new IllegalArgumentException("No se cumplen las condiciones "
                    + "para realizar la operación de asignación...");
        }

    }

    private boolean condicionesPunteros() {
        if (nodoInicial.getClase() == Clase.PUNTERO) {
            return true;
        }
        return false;
    }

    private Nodo malloc() {
        if (condicionesPunteros()) {
            nodoInicial.setOperacion("MALLOC");
            return nodoInicial;
        } else {
            throw new IllegalArgumentException("La operación malloc sólo "
                    + "se puede realizar sobre punteros...");
        }
    }

    private Nodo free() {
        if (condicionesPunteros()) {
            nodoInicial.setOperacion("FREE");
            return nodoInicial;
        } else {
            throw new IllegalArgumentException("La operación free sólo "
                    + "se puede realizar sobre punteros...");
        }
    }

    private String generarCodigoNASMacceso() {
        //no tiene
        return null;
    }

    private String generarCodigoNASMasignacion() {
        //no tiene
        return null;
    }

    private String generarCodigoNASMmalloc() {
        return "call malloc " + nodoInicial.getNombre();
    }

    private String generarCodigoNASMfree() {
        return "call free [" + nodoInicial.getNombre() + "]";
    }
}
